home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
answrbok
/
6_11.lha
/
6_11
/
6_11_div.c
< prev
next >
Wrap
Text File
|
1993-08-08
|
8KB
|
393 lines
* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
* The C++ Answer Book */
* Tony Hansen */
* All rights reserved. */
*
Divide u[1..m+n] by v[1..n] to form
q[0..m] and r[1..n]
Based on:
The Art of Computer Programming, volume 2
D. Knuth, Section 4.3.1, Algorithm D and
exercise 16.
/
include <arbint.h>
include <debug.h> /* DELETE */
oid dodivmod(const arbint &tmp_u, const arbint &tmp_v,
arbint "ient, arbint &remainder)
// Make u (the dividend) and
// v (the divisor) positive.
int negu = tmp_u.isneg();
int negv = tmp_v.isneg();
arbint u(+tmp_u);
if (negu) u = -tmp_u;
arbint v(+tmp_v);
if (negv) v = -tmp_v;
f (debug&16) outputarb(cerr, "u=", u.p->value, u.p->length, u.p->refcnt); // DELETE
f (debug&16) outputarb(cerr, "v=", v.p->value, v.p->length, v.p->refcnt); // DELETE
/*
The sign of the remainder will
match the sign of the dividend.
The sign of the quotient will be
negative if the sign of the divisor
and dividend do not match, else
positive.
*/
int negremainder = negu;
int negquotient = (negu != negv);
f (debug&16) cerr << "neg remainder=" << negremainder << ", neg quotient=" << negquotient << "\n"; // DELETE
// Set local variables.
ARB_type *uv = u.p->value;
ARB_type *vv = v.p->value;
int m_n = u.p->length; // m + n
int n = v.p->length;
int m = m_n - n;
f (debug&16) cerr << "m+n=" << m_n << ", n= " << n << ", m=" << m << "\n"; // DELETE
/*
For n == 1, use simpler algorithm
*/
if (n == 1)
{
f (debug&16) cerr << "n==1, simpler algorithm\n"; // DELETE
if (vv[0] == 0)
{
error("division by zero!");
quotient = remainder = +u;
}
else
{
/*
See Exercise 16 after Section 4.3.1
*/
ARB_type *qv = new ARB_type[m_n];
ARB_Ltype prevu = 0;
ARB_type v1 = vv[0];
for (int r = 0; r < m_n; r++)
{
ARB_Ltype t = uv[r] + prevu * ARB_base;
ARB_type tmpq = t / v1;
qv[r] = tmpq; // % ARB_base
prevu = t - v1 * tmpq;
}
arbint q(qv, m_n);
if (negquotient)
quotient = -q;
else
quotient = q;
if (negremainder)
remainder = -prevu;
else
remainder = prevu;
}
return;
}
/*
Degenerate case of length(u) < length(v)
i.e., m < 0, implying that u < v
*/
else if (m_n < n)
{
f (debug&16) cerr << "m_n < n, quotient <- 0\n"; // DELETE
quotient = 0L;
if (negremainder)
remainder = -u;
else
remainder = +u;
return;
}
/*
Degenerate case of length(u) == length(v)
i.e., m == 0, possibly implying that
u < v or u == v
*/
else if (m_n == n)
{d
bug&16) cerr << "m_n == n\n"; // DELETE
int cmp = arb_cmp(uv, vv, m_n);
if (cmp < 0) // u < v
{d
bug&16) cerr << "\tquotient == 0\n"; // DELETE
quotient = 0L;
if (negremainder)
remainder = -u;
else
remainder = +u;
return;
}
else if (cmp == 0) // u == v
{
f (debug&16) cerr << "\tremainder == 0\n"; // DELETE
if (negquotient)
quotient = -1L;
else
quotient = 1L;
remainder = 0L;
return;
}
}
/*
Now call out all of the guns from Knuth
*/
f (debug&16) cerr << "all the guns\n"; // DELETE
// In rare circumstances, the first
// digit of u or v may be 0. This digit
// must now be discarded.
while ((*uv == 0) && (m_n > 1))
{ uv++; m_n--; }
while ((*vv == 0) && (n > 1))
{ vv++; n--; }
m = m_n - n;d
bug&16) cerr << "m+n=" << m_n << ", n= " << n << ", m=" << m << "\n"; // DELETE
f (debug&16) outputarb(cerr, "uv=", uv, m_n); // DELETEd
bug&16) outputarb(cerr, "vv=", vv, n); // DELETE
/*
D1(a) [Normalize.]
Set d <- b/(v1+1).
*/
ARB_type d = ARB_base / (vv[0] + 1);
f (debug&16) cerr << "D1: normalize\n"; // DELETEd
bug&16) cerr << "d=" << d << "\n"; // DELETEd
/*
D1(b) [Normalize.]
Set (u[0]u[1]...u[m+n]) to
(u[1]u[2]...u[m+n]) * d
*/
ARB_type *Ouv = uv;
ARB_type k;
uv = new ARB_type[m_n + 1];
if (d == 1)
{
// copy old value
uv[0] = 0;
memcpy((char*)&uv[1], (char*)&Ouv[0],
m_n * sizeof(ARB_type));
}
else
{
// multiply u by d
k = 0;
for (int Oi = m_n - 1, i = m_n;
i > 0;
Oi--, i--)
{
ARB_Ltype t = Ouv[Oi] * d + k;
uv[i] = t; // % ARB_base;
k = t / ARB_base;
}
uv[i] = k;
}
f (debug&16) outputarb(cerr, "uv=", uv, m_n+1); // DELETE
/*
D1(c) [Normalize.]
Set (v[1]v[2]...v[n]) to
(v[1]v[2]...v[n]) * d
*/
ARB_type *Ovv = vv;
vv = new ARB_type[n];
if (d == 1)
{d // copy old value
memcpy((char*)&vv[0], (char*)&Ovv[0],
n * sizeof(ARB_type));
}
else
{
// multiply v by d
k = 0;
for (int Oi = n - 1, i = n - 1;
i >= 0;
Oi--, i--)
{
ARB_Ltype t = Ovv[Oi] * d + k;
vv[i] = t; // % ARB_base;
k = t / ARB_base;
}
}d
bug&16) outputarb(cerr, "vv=", vv, n); // DELETE
/*
D2 [Initialize j]
Set j <- 0
D7 [Loop on j]
Set j <- j+1
Loop if j <= m
*/
ARB_type v1 = vv[0];
ARB_type v2 = vv[1];
ARB_type *qv = new ARB_type[m + 1];
ARB_type *nv = new ARB_type[n + 1];
for (int j = 0; j <= m; j++)
{
/*
D3 [Calculate q^]
If u[j] == v[1]
Set q^ <- base - 1
Else
Set q^ <-
(u[j] * base + u[j+1]) / v[1]
While v[2] * q^ >
(u[j] * base + u[j+1] - q^ * v[1]) *
base + u[j+2]
Set q^ <- q^ - 1
*/
ARB_Ltype q_hat;
if (uv[j] == v1)
q_hat = ARB_base - 1;
else
q_hat = (uv[j] * ARB_base + uv[j+1]) / v1;d
bug&16) cerr << "D3: calculate q^, j=" << j << "\n"; // DELETEdif (debug&16) cerr << "\tq^=" << q_hat << "\n"; // DELETE
ARB_Ltype u_j = uv[j];
ARB_Ltype u_j1 = uv[j+1];
ARB_Ltype u_j2 = uv[j+2];
for ( ; ; q_hat--)
{d /*
if ((v2 * q_hat) <=
((u_j * ARB_base + u_j1 -
v1 * q_hat) * ARB_base + u_j2))
q^--;
*/
ARB_Ltype u_j_q_hat = u_j * ARB_base + u_j1;
u_j_q_hat -= v1 * q_hat;
if (u_j_q_hat / ARB_base != 0)
break;
u_j_q_hat *= ARB_base;
u_j_q_hat += u_j2;
if ((v2 * q_hat) <= u_j_q_hat)
break;
}
f (debug&16) cerr << "q^=" << q_hat << "\n"; // DELETE
/*
D4 [Multiply and subtract.]
Replace u[j..j+n] by
u[j..j+n] -
q^ * v[1..n]
*/d
bug&16) cerr << "D4: multiply and subtract\n"; // DELETEd // set nv <- q^ * (v[1..n])
k = 0;
for (int dl = n, vl = n-1; vl >= 0; vl--, dl--)
{
ARB_Ltype t = vv[vl] * q_hat + k;
nv[dl] = t; // % ARB_base;
k = t / ARB_base;
}
nv[0] = k;
// subtract nv[0..n] from u[j..j+n]
int borrow = 0;
int ul = j + n;
for (dl = n; dl >= 0; dl--, ul--)
{
ARB_Ltype t = uv[ul] - nv[dl] - borrow;
uv[ul] = t; // % ARB_base
borrow = (t / ARB_base) ? 1 : 0;
}
/*
D5 [Test remainder]
Set q[j] <- q^
if u[j] < 0
D6 [Add back]
add 0v[1..n] back to u[j..j+n]
q[j]--
*/
qv[j] = q_hat;d
bug&16) cerr << "D5: test remainder\n"; // DELETEdif (debug&16) cerr << "\tqv[" << j << "]=" << q_hat << "\n"; // DELETEdif (debug&16) cerr << "\tborrow=" << borrow << "\n"; // DELETE
if (borrow != 0)
{
for (k = 0, ul = j + n, vl = n - 1;
vl >= 0;
vl--, ul--)
{d ARB_Ltype t = uv[ul] + vv[vl] + k;
uv[ul] = t; // % ARB_base
k = t / ARB_base;
}
uv[j] += k;
qv[j]--;d
bug&16) cerr << "\tqv[" << j << "]=" << q_hat << "\n"; // DELETE
}
}
/*
D8 [Unnormalize]
q[0..m] is quotient
u[m+1..m+n] / d is remainder
*/
f (debug&16) outputarb(cerr, "q=", qv, m+1); // DELETE
arbint q(qv, m+1);
if (negquotient)
quotient = -q;
else
quotient = q;
f (debug&16) outputarb(cerr, "quotient=", quotient.p->value, quotient.p->length); // DELETE
// divide u[m+1..m+n] by d
ARB_type *rem = new ARB_type[n];
if (d == 1) // nothing special to do
memcpy((char*)rem, (char*)&uv[m+1],
n * sizeof(ARB_type));
elsRB_type))
// do division by single digit
for (int rl = 0, ul = m + 1;
ul <= m_n;
ul++, rl++)
{
ARB_Ltype t = uv[ul] + prevu * ARB_base;
ARB_type tmpq = t / d;
rem[rl] = tmpq; // % ARB_base
prevu = t - d * tmpq;
}
}
f (debug&16) outputarb(cerr, "rem=", rem, n); // DELETE
arbint r(rem, n);
if (negremainder)
remainder = -r;
else
remainder = r;d
bug&16) outputarb(cerr, "remainder=", remainder.p->value, remainder.p->length); // DELETE
delete uv; delete vv; delete nv;
rbint operator%(const arbint &u, const arbint &v)
arbint quot, rem;
dodivmod(u, v, quot, rem);
return rem;
rbint operator/(const arbint &u, const arbint &v)
arbint quot, rem;
dodivmod(u, v, quot, rem);
return quot;